﻿#include "writewidget.h"

void printWidget(QXmlStreamWriter &writer, QString originX, QString oringinY, QString wWidth, QString wHeight, QString widgetLibLoc, const QList<Parameter>& inputParameters, const Extensions& extensions)
{
    /*========visible========*/
    writer.writeStartElement("visible");
    writer.writeStartElement("init");
    writer.writeCharacters("true");
    writer.writeEndElement();
    writer.writeEndElement();

    /*========origin========*/
    writer.writeStartElement("origin");
    writer.writeStartElement("x");
    writer.writeStartElement("init");
    writer.writeCharacters(originX);
    writer.writeEndElement();
    writer.writeEndElement();
    writer.writeStartElement("y");
    writer.writeStartElement("init");
    writer.writeCharacters(oringinY);
    writer.writeEndElement();
    writer.writeEndElement();
    writer.writeEndElement();

    /*========width========*/
    writer.writeStartElement("width");
    writer.writeStartElement("init");
    writer.writeCharacters(wWidth);
    writer.writeEndElement();
    writer.writeEndElement();

    /*========height========*/
    writer.writeStartElement("height");
    writer.writeStartElement("init");
    writer.writeCharacters(wHeight);
    writer.writeEndElement();
    writer.writeEndElement();

    /*========file========*/
    writer.writeStartElement("file");
    writer.writeAttribute("name", widgetLibLoc);
    writer.writeEndElement();

    /*========include========*/
    writer.writeStartElement("include");
    writer.writeAttribute("path", "./include");
    writer.writeEndElement();

    /*========inputParameters========*/
    writer.writeStartElement("inputParameters");

    for(int i = 0; i < inputParameters.count(); i++)
    {
        Parameter inputParameter = inputParameters.at(i);
        writer.writeStartElement("parameters");
        writer.writeAttribute("name", inputParameter.name);

        writer.writeStartElement("init");
        writer.writeCharacters(inputParameter.initValue);
        writer.writeEndElement();

        writer.writeEndElement();
    }



    writer.writeEndElement();

    /*========outputParameters========*/
    writer.writeStartElement("outputParameters");
    writer.writeEndElement();

}

// 辅助函数：写入基本属性
void printBasicProperties(QXmlStreamWriter& writer, const DllProperties& dllProperties,
                          int oX, int oY, int wWidth, int wHeight) {
    // 写入visible
    writer.writeStartElement("visible");
    writer.writeStartElement("init");
    writer.writeCharacters(dllProperties.visible.value);
    writer.writeEndElement(); // init
    writer.writeEndElement(); // visible

    // 写入origin
    writer.writeStartElement("origin");
    writer.writeStartElement("x");
    writer.writeStartElement("init");
    writer.writeCharacters(QString::number(oX));
    writer.writeEndElement(); // init
    writer.writeEndElement(); // x
    writer.writeStartElement("y");
    writer.writeStartElement("init");
    writer.writeCharacters(QString::number(oY));
    writer.writeEndElement(); // init
    writer.writeEndElement(); // y
    writer.writeEndElement(); // origin

    // 写入width和height
    writer.writeStartElement("width");
    writer.writeStartElement("init");
    writer.writeCharacters(QString::number(wWidth));
    writer.writeEndElement(); // init
    writer.writeEndElement(); // width

    writer.writeStartElement("height");
    writer.writeStartElement("init");
    writer.writeCharacters(QString::number(wHeight));
    writer.writeEndElement(); // init
    writer.writeEndElement(); // height
}

// 辅助函数：写入文件相关属性
void printFileProperties(QXmlStreamWriter& writer, const DllProperties& dllProperties, const Rule& rule) {
    // 写入file
    writer.writeStartElement("file");
    //writer.writeAttribute("name", dllProperties.name);   //24
    //writer.writeAttribute("path", "widget/a661");    //24
    QString dllName = dllProperties.type;
    dllName = dllName.toLower();
    if(dllName.startsWith("gp"))
    {
        dllName.remove(0,2);
    }
    writer.writeAttribute("name", "lib" + dllName);
    writer.writeAttribute("path", "widget/a661");
    writer.writeEndElement(); // file

    // 写入include
    writer.writeStartElement("include");
    //writer.writeAttribute("path", dllProperties.include.path);
    writer.writeAttribute("path", "./include");
    writer.writeEndElement(); // include

    int intCount = 0;
    int realCount = 0;
    int charCount = 0;
    for(Prop prop : rule.widget.model.definition.props){

    }

    writer.writeStartElement("propsCount");
    writer.writeAttribute("intCount", QString::number(intCount));
    writer.writeAttribute("realCount", QString::number(realCount));
    writer.writeAttribute("charCount", QString::number(charCount));
    writer.writeEndElement(); // file


}

// 辅助函数：写入单个参数
void printParameter(QXmlStreamWriter& writer, Parameter& param, const PropTypes &propTypes, const Prop &prop, const QMap<QString, QString> &constMap, bool isSymbol = false) {
    writer.writeStartElement("parameter");
    writer.writeAttribute("name", param.name);
    if(param.name == "BufferStructure"){

        QString result;
        QString input = param.initValue;
        QStringList parts = input.split(QRegularExpression("(?<=\\d)(?=\\D)"), Qt::KeepEmptyParts);

        QRegularExpression re("(\\d+)([A-Za-z_]+\\d+[A-Za-z_]*)");
        int lastPos = 0;
        auto it = re.globalMatch(input);

        while (it.hasNext()) {
            auto match = it.next();

            if (!result.isEmpty()) {
                result += ";";
            }
            result += "(" + match.captured(1) + "," + match.captured(2) + ")";
            lastPos = match.capturedEnd();
        }

        writer.writeStartElement("init");
        writer.writeCharacters(result);
        writer.writeEndElement(); // init
        writer.writeEndElement(); // parameter
        return;
    }


    // 动态设置 type 属性
    if(param.type == "stringprop"){
        writer.writeAttribute("type", "char");
    }
    else if(param.type == "floatprop"){
        writer.writeAttribute("type", "real");
    }
    else{
        writer.writeAttribute("type", "int");
    }

    if (prop.type == "enumprop" && !(param.name == "StyleSet" || param.name == "PictureReference")) {
        writer.writeAttribute("enumType", prop.enumType);
        if (constMap.contains(param.enumValue)) {
            param.initValue = constMap[param.enumValue];
        } else {
            // 如果没有找到映射，可以设置默认值或记录警告
            param.initValue = "0";
        }
    }
    if (param.name == "ColorIndex" || param.name == "FillIndex") {
        writer.writeAttribute("enumType", "900001");
    }

    writer.writeStartElement("init");
//    if(isSymbol){
//        writer.writeCharacters("50");
//    }
//    else{
        QString initValue = param.initValue;
        if(param.type != "stringprop" && param.type != "floatprop"){
            initValue = initValue.split('.').first();
        }
        writer.writeCharacters(initValue);
//    }
    writer.writeEndElement(); // init

    if (!param.enumValue.isEmpty()) {
        writer.writeStartElement("enum");
        writer.writeCharacters(param.enumValue);
        writer.writeEndElement(); // enum
    }

    writer.writeEndElement(); // parameter
}

// 辅助函数：写入输入/输出参数
void printParameters(QXmlStreamWriter& writer, const QList<Parameter>& parameters
                     , const QString& elementName, const Rule &rule, const PropTypes &propTypes, const QMap<QString, QString> &constMap) {
    writer.writeStartElement(elementName);
    if (parameters.isEmpty()) {
        writer.writeEndElement();
        return;
    }

    QList<Prop> props = rule.widget.model.definition.props;

    int minSize = std::min(props.size(), parameters.size());

    for (int i = 0; i < minSize; ++i) {
        const Prop& prop = props[i];
        Parameter param = parameters[i];

        // 只有当相同位置的 name 匹配时才处理
        if (prop.name == param.name) {
            if(rule.name == "Symbol" && (param.name == "PosX" || param.name == "PosY")){
                printParameter(writer, param, propTypes, prop, constMap, true);
            }
            else{
                printParameter(writer, param, propTypes, prop, constMap);
            }
        }
    }

    writer.writeEndElement(); // elementName
}

// 辅助函数：写入扩展属性
void printExtensions(QXmlStreamWriter& writer, Extensions& extensions, const ExtensionRules &eRules, const PropTypes &propTypes) {
    if (extensions.extensionList.isEmpty()) {
        return;
    }

    writer.writeStartElement("extensions");
    for (const Extension& ext : extensions.extensionList) {

        auto it = std::find_if(eRules.extensionRules.begin(),eRules.extensionRules.end(),
                               [&ext](const ExtensionRule& eRule) {
                                   return eRule.name == ext.name;
                               });
        if (it != eRules.extensionRules.end()) {
            const ExtensionRule& matchedeRule = *it;  // 获取匹配的 eRule 的引用
            QList<Prop> props = matchedeRule.widgetExtension.model.definition.props;

            if(ext.eParams.size() == props.size())
            {
                writer.writeStartElement("extension");
                writer.writeAttribute("name", ext.name);
                writer.writeAttribute("enable", "1");

                for (int i = 0; i < ext.eParams.size(); ++i) {
                    Parameter param = ext.eParams[i];
                    const Prop &prop = props[i];
                    if(param.name != prop.name)       //判断prop名字是否与规则一致
                    {
                        continue;
                    }
                    writer.writeStartElement("parameter");
                    writer.writeAttribute("name", param.name);
                    QString type = param.type;
                    QString typechopped = type.chopped(4);
                    if(typechopped != "int" && typechopped != "enum"){
                        typechopped = "char";
                    }
                    writer.writeAttribute("type", typechopped);
                    if(param.type == "enumprop"){
                        writer.writeAttribute("enumType", prop.enumType);
                        if (propTypes.enum2initMap.contains(param.enumValue)) {
                            param.initValue = propTypes.enum2initMap[param.enumValue];
                        } else {
                            // 如果没有找到映射，可以设置默认值或记录警告
                            param.initValue = "0"; // 默认值
                        }
                    }

                    writer.writeStartElement("init");
                    writer.writeCharacters(param.initValue);
                    writer.writeEndElement(); // init

                    if(param.type == "enumprop"){
                        writer.writeStartElement("enum");
                        writer.writeCharacters(param.enumValue);
                        writer.writeEndElement();
                    }

                    writer.writeEndElement(); // parameter

                }

                writer.writeEndElement(); // extension
            }
        }
    }
    writer.writeEndElement(); // extensions
}

// 辅助函数：写入事件
void printWidgetEvents(QXmlStreamWriter& writer, const QString& layerId, const QString& widgetId, QString name
                       , const CommuParams &commuParams, const SdyContent &sdys) {
    // Find the widget with the specified name
    const ComWidget* widget = nullptr;
    for (const auto& w : commuParams.widgets) {
        if (w.name == name) {
            widget = &w;
            break;
        }
    }

    if (!widget) {
        return;
    }

    // Write notifys section
    if(widget->ntfs.size() != 0){
        writer.writeStartElement("notifys");
        for (const Event& ntf : widget->ntfs) {
            QString parameter = ntf.name; // e.g. "A661_EVT_STRING_CHANGE_ABORTED"

            for (const Variable& var : ntf.vars) {
                writer.writeStartElement("notify");
                writer.writeAttribute("id", var.id);
                writer.writeAttribute("name", var.name);
                QString type = var.type;
                if(type == "int16"){
                    type = "short";
                }
                else if(type == "uint16"){
                    type = "ushort";
                }
                else if(type == "int32"){
                    type = "int";
                }
                else if(type == "uint32"){
                    type = "uint";
                }
                else if(type == "int64"){
                    type = "int64";
                }
                else if(type == "uint64"){
                    type = "uint64";
                }
                else if(type == "float32"){
                    type = "float";
                }
                else if(type == "float64"){
                    type = "real";
                }
                writer.writeAttribute("type", type);
                writer.writeAttribute("tag", "A661_NOTIFY_WIDGET_EVENT");
                writer.writeAttribute("parameter", parameter);

                for(const MappingItem& item : sdys.inputItems){
                    QString eName = item.eventVar.name;
                    eName.replace("Evt", "");
                    if(layerId == item.eventVar.layerId && widgetId == item.eventVar.widgetId && parameter == item.eventVar.paramId
                        && var.name == eName){
                        writer.writeStartElement("control_var");
                        writer.writeAttribute("name", item.conVar.name);
                        writer.writeAttribute("type", item.conVar.type);
                        QString path = item.conVar.instancepath;
                        if(path.endsWith('/')){
                            path.chop(1);
                        }
                        writer.writeAttribute("path", path);
                        writer.writeAttribute("scope", "inputs");
                        writer.writeAttribute("subelement", item.conVar.subelement);
                        writer.writeEndElement();
                        break;
                    }
                }

                writer.writeEndElement(); // notify
            }
        }
        writer.writeEndElement(); // notifys
    }

    if(widget->msgs.size() != 0){
        // Write messages section
        writer.writeStartElement("messages");
        for (const Event& msg : widget->msgs) {
            QString parameter = msg.name; // e.g. "A661_ENABLE"

            for (const Variable& var : msg.vars) {
                writer.writeStartElement("message");
                writer.writeAttribute("id", var.id);
                writer.writeAttribute("name", var.name);
                 QString type = var.type;
                if(type == "int16"){
                    type = "short";
                }
                else if(type == "uint16"){
                    type = "ushort";
                }
                else if(type == "int32"){
                    type = "int";
                }
                else if(type == "uint32"){
                    type = "uint";
                }
                else if(type == "int64"){
                    type = "int64";
                }
                else if(type == "uint64"){
                    type = "uint64";
                }
                else if(type == "float32"){
                    type = "float";
                }
                else if(type == "float64"){
                    type = "real";
                }
                writer.writeAttribute("type", type);
                writer.writeAttribute("tag", "A661_CMD_SET_PARAMETER");
                writer.writeAttribute("parameter", parameter);

                for(const MappingItem& item : sdys.outputItems){
                    if(layerId == item.eventVar.layerId && widgetId == item.eventVar.widgetId && parameter == item.eventVar.paramId
                        && var.name == item.eventVar.name){
                        writer.writeStartElement("control_var");
                        writer.writeAttribute("name", item.conVar.name);
                        writer.writeAttribute("type", item.conVar.type);
                        QString path = item.conVar.instancepath;
                        if(path.endsWith('/')){
                            path.chop(1);
                        }
                        writer.writeAttribute("path", path);
                        writer.writeAttribute("scope", "outputs");
                        writer.writeAttribute("subelement", item.conVar.subelement);
                        writer.writeEndElement();
                        break;
                    }
                }

                writer.writeEndElement(); // message
            }
        }
        writer.writeEndElement(); // messages
    }

}

void transNum(QList<Parameter> &paramers, int &oX, int &oY, int &wWidth, int &wHeight, int layerWidth, int layerHeight, PropTypes propTypes){
    int x1, x2, y1, y2;
    for(Parameter &param: paramers){
        if(propTypes.posXList.contains(param.name)){
            if(param.name == "PosX"){
                int x = param.initValue.toFloat() / 20 - layerWidth / 2;
                x1 = x;
                param.initValue = "0";
            }
            else if(param.name == "PosX2"){
                param.initValue = QString::number(param.initValue.toFloat() / 20 - layerWidth / 2 - x1);
            }
            else if(param.name == "PosX3"){
                x2 = param.initValue.toFloat() / 20 - layerWidth / 2;
                wWidth = std::abs(x2 - x1);
                param.initValue = QString::number(x2 - x1);
            }
            else if(param.name == "PosXStart"){
                int x = param.initValue.toFloat() / 20 - layerWidth / 2;
                x1 = x;
                param.initValue = "0";
            }
            else if(param.name == "PosXEnd"){
                x2 = param.initValue.toFloat() / 20 - layerWidth / 2;
                wWidth = std::abs(x2 - x1);
                param.initValue = QString::number(x2 - x1);
            }
        }
        else if(propTypes.posYList.contains(param.name)){
            if(param.name == "PosY"){
                int y = param.initValue.toFloat() / 20 - layerHeight / 2;
                y1 = y;
                param.initValue = "0";
            }
            else if(param.name == "PosY2"){
                param.initValue = QString::number(param.initValue.toFloat() / 20 - layerHeight / 2 - y1);
            }
            else if(param.name == "PosY3"){
                y2 = param.initValue.toFloat() / 20 - layerHeight / 2;
                wHeight = std::abs(y2 - y1);
                param.initValue = QString::number(y2 - y1);
            }
            else if(param.name == "PosYStart"){
                int y = param.initValue.toFloat() / 20 - layerHeight / 2;
                y1 = y;
                param.initValue = "0";
            }
            else if(param.name == "PosYEnd"){
                y2 = param.initValue.toFloat() / 20 - layerHeight / 2;
                wHeight = std::abs(y2 - y1);
                param.initValue = QString::number(y2 - y1);
            }
        }
        else if(propTypes.m20List.contains(param.name)){
            param.initValue = QString::number(param.initValue.toFloat() / 20);
            if(param.name == "SizeX"){
                wWidth = param.initValue.toInt();
            }
            else if(param.name == "SizeY"){
                wHeight = param.initValue.toInt();
            }
            else if(param.name == "Radius"){
                wWidth = wHeight = param.initValue.toInt();
            }
        }
        else if(propTypes.angleList.contains(param.name)){
            param.initValue = QString::number(param.initValue.toFloat() / 11930465);
        }
    }
    if(wWidth == 0){
        wWidth = 20;
    }
    if(wHeight == 0){
        wHeight = 15;
    }
}

// 主函数
void printWidgetContainer(QXmlStreamWriter& writer, const QString& layerId, const DllProperties& dllProperties, QString oid, int oX, int oY, int wWidth, int wHeight
                          , int layerWidth, int layerHeight, const Rule& rule, const ExtensionRules& eRules, const PropTypes &propTypes
                          , int inContainer, const QMap<QString, QString> &constMap, const CommuParams &commuParams, const SdyContent &sdys) {
    // 写入properties
    writer.writeStartElement("properties");
    writer.writeAttribute("name", dllProperties.name);
    writer.writeAttribute("type", dllProperties.type);

    if (rule.isContainer) {
        writer.writeAttribute("container", "true");
    }

    QList<Parameter> params = dllProperties.inputParameters.paramers;
    Extensions exts = dllProperties.extensions;

    transNum(params, oX, oY, wWidth, wHeight, layerWidth, layerHeight, propTypes);

    if(rule.name == "Symbol"){
        wWidth = 50;
        wHeight = 50;
    }

    // 写入基本属性
    printBasicProperties(writer, dllProperties, oX, oY, wWidth, wHeight);

    // 写入文件相关属性
    printFileProperties(writer, dllProperties, rule);

    // 写入输入参数
    printParameters(writer, params, "inputParameters", rule, propTypes, constMap);

    // 写入输出参数
    printParameters(writer, dllProperties.outputParameters.paramers, "outputParameters", rule, propTypes, constMap);

    // 写入扩展属性
    printExtensions(writer, exts, eRules, propTypes);

    QString widgetId = params.at(0).initValue;

    // 写入事件
    printWidgetEvents(writer, layerId, widgetId, rule.name, commuParams, sdys);

    writer.writeEndElement(); // properties
    //writer.writeEndElement(); // widgetContainer
}
